package workers

import (
	"black_mamba/global"
	"black_mamba/utils"
	"fmt"
	"gitee.com/wengo/go-amazon"
	"gitee.com/wengo/go-mamba"
	"github.com/PuerkitoBio/goquery"
	"github.com/tidwall/gjson"
	"io/ioutil"
	"runtime/debug"
	"strconv"
	"strings"
	"sync"
	"time"
)

type DealsCheckoutWorker struct {
	Worker
	//FeedBackCallback func(int) int
}

func NewDealsCheckoutWorker() *DealsCheckoutWorker {
	return &DealsCheckoutWorker{
		Worker{
			Topic: "deals",
		},
	}
}

func (d *DealsCheckoutWorker) AddCartThread(data map[string]interface{}) (ret interface{}) {

	amz := data["amz"].(*amazon.Amazon)
	asin := data["asin"].(string)
	quantity := data["quantity"].(int)
	sellerId := data["seller_id"].(string)
	zipcode := data["zipcode"].(string)
	email := data["email"].(string)
	groupName := data["group"].(string)

	if quantity < 600 {
		quantity = amazon.RandomInt(400, 499)
	} else {
		quantity = amazon.RandomInt(700, 980)
	}

	// 打开跟卖
	d.sendLog(map[string]string{"status": "info", "email": email, "group": groupName, "content": fmt.Sprintf("获取 %s 的跟卖商家", asin)})
	_, document, err := amz.GetOfferListing(asin)

	if err != nil {
		d.sendLog(map[string]string{"status": "error", "email": email, "group": groupName, "content": fmt.Sprintf("%s -> %s", asin, err.Error())})
		return
	}

	resultQty, err := amz.AddCartByOffers(document, asin, sellerId, quantity)

	if err != nil {
		//resp, _, chkerr := amz.Navigate(amazon.TestLogin)
		//if chkerr != nil {
		//	d.sendLog(map[string]string{"status": "error", "email": email, "group": groupName, "content": fmt.Sprintf("判断账户失效失败, %s", chkerr.Error())})
		//} else if resp.RawResponse.Request.URL.Path == "/ap/signin"{
		//	d.sendLog(map[string]string{"status": "error", "email": email, "group": groupName, "content": "账户需要登录"})
		//} else {
		//
		//}
		d.sendLog(map[string]string{"status": "error", "email": email, "group": groupName, "content": fmt.Sprintf("%s, 当前地址邮编 : %s", err.Error(), zipcode)})
	} else if resultQty == 0 {
		d.sendLog(map[string]string{"status": "error", "email": email, "group": groupName, "content": fmt.Sprintf("%s 加购数量为 %d", asin, resultQty)})
	} else {
		d.sendLog(map[string]string{"status": "info", "email": email, "group": groupName, "content": fmt.Sprintf("%s 计划加购数量 %d, 实际加购数量为 %d", asin, quantity, resultQty)})
		ret = map[string]string{
			"status": "success",
			"qty":    strconv.Itoa(int(resultQty)),
			"asin":   asin,
		}
	}

	return

	// 打开Listing
	/* 旧版本
	d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group":groupName,  "content": fmt.Sprintf("查看 %s listing", asin)})
	_, document, err := amz.Navigate(fmt.Sprintf("/dp/%s/ref=sr_1_2?m=%s&sr=1-1", asin, sellerId))
	if err != nil {
		d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group":groupName,  "content": err.Error()})
		return
	}

	html, _ := document.Html()
	ioutil.WriteFile(fmt.Sprintf("%s.html", asin), []byte(html), 0644)

	if !amz.CheckListingHasCart(document) {
		d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group":groupName,  "content": fmt.Sprintf("%s 没有购物车按钮，不加购", asin)})
		return
	}

	// 加入购物车
	document, err = amz.AddCart(document, quantity)
	if err != nil {
		d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group":groupName,  "content": fmt.Sprintf("%s 加入购物车失败", asin)})
		return
	}

	if !amz.CheckAddCartSuccess(document) {
		d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group":groupName,  "content": fmt.Sprintf("%s 加入购物车失败", asin)})
		html, _ = document.Html()
		ioutil.WriteFile(fmt.Sprintf("%s-addcart.html", asin), []byte(html), 0644)
		return
	} else {
		d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group":groupName,  "content": fmt.Sprintf("%s 加入购物车成功", asin)})
	}*/

}

func (d *DealsCheckoutWorker) HeartbeatThread(data map[string]interface{}) (ret interface{}) {
	ticker := time.NewTicker(1 * time.Minute)
	index := 1
	total := data["pauseTime"].(int64)
	amz := data["amz"].(*amazon.Amazon)
	email := data["email"].(string)
	groupName := data["group"].(string)

	for {
		<-ticker.C
		if index >= int(total) {
			ticker.Stop()
			return true
		} else {
			resp, _, err := amz.Navigate(amazon.TestLogin)
			if err != nil {
				d.sendLog(map[string]string{"status": "info", "email": email, "group": groupName, "content": err.Error()})
			} else {
				if resp.RawResponse.Request.URL.Path == "/ap/signin" {
					ticker.Stop()
					return false
				} else {
					d.sendLog(map[string]string{"status": "info", "email": email, "group": groupName, "content": "账户依然存活"})
				}
			}

		}
		index++
	}
}

func (d *DealsCheckoutWorker) Execute(data map[string]interface{}) (ret interface{}) {
	/*
		   流程
		    1.访问首页
			2.新建收货地址，新建信用卡
			3.打开Listing
			4.加入购物车
			5.结账
			6.选择地址
			7.选择信用卡
			8.建立订单
	*/
	defer func() {
		//可以打印错误信息
		//recover()
		//fmt.Println(recover())

		//没有错就不要打印
		if err := recover(); err != nil { //产生了panic异常
			stackStr := string(debug.Stack())
			utils.WriteFile("worker_error.log", fmt.Sprintf("%s\n%s\n", err, stackStr))
			d.sendLog(map[string]string{"status": "error", "content": fmt.Sprintf("软件异常,退出, 原因 = %s", err)})
			fmt.Println(stackStr)
			global.BM_EVENTBUS.Publish(fmt.Sprintf("%s:deleteData", d.Topic), data["group"].(string))
			d.EndFeedBack(data["tasks"], 0)
		}
	}()

	groupName := data["group"].(string)
	pauseTime := data["pauseTime"].(int64)

	var resp *mamba.Response
	var document *goquery.Document
	var err error
	var addcartWg sync.WaitGroup
	var heartbeatWg sync.WaitGroup

	website := gjson.Get(data["tasks"].(string), "list.0.website.value").String()
	code := gjson.Get(data["tasks"].(string), "list.0.code.value").String()
	var isCancel bool
	if gjson.Get(data["tasks"].(string), "list.0.payment_type.value").String() == "no_payment" {
		isCancel = false
	} else {
		isCancel = true
	}

	proxy := fmt.Sprintf("http://%s:%s@tunnel5.qg.net:14295", global.BM_CONFIG.Section("proxy").Key("username").Value(), global.BM_CONFIG.Section("proxy").Key("password").Value())
	//proxy := fmt.Sprintf("http://%s", data["proxy"].(string))
	//proxy := ""
	// 检查ip
	result, e := utils.CheckIp(proxy)
	if e != nil {
		d.sendLog(map[string]string{"status": "error", "content": "无法连接代理服务器"})
		global.BM_EVENTBUS.Publish(fmt.Sprintf("%s:deleteData", d.Topic), groupName)
		d.EndFeedBack(data["tasks"], 0)
		return
	}

	d.sendLog(map[string]string{"status": "info", "group": groupName, "content": fmt.Sprintf("代理ip => %s", gjson.Get(result.String(), "ip").String())})

	// 获取cookies
	d.sendLog(map[string]string{"status": "info", "group": groupName, "content": "获取账户信息"})

	//user, err := global.BM_API.GetCookies("us")
	// 德国
	user, err := global.BM_API.GetCookies(code, global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value())

	if err != nil {
		d.sendLog(map[string]string{"status": "error", "content": "获取用户信息失败"})
		global.BM_EVENTBUS.Publish(fmt.Sprintf("%s:deleteData", d.Topic), groupName)
		d.EndFeedBack(data["tasks"], 0)
	}

	d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("邮箱地址 -> %s", user.Emailaddress)})
	d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("用户密码 -> %s", user.Password)})
	d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("%s", user.Cookies)})

	//if !d.patchLogin(user) {
	//	return
	//}
	amz := amazon.NewAmazon(amazon.Settings{
		//JA3:       "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,29-23-24,0",
		//UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",
		JA3:       "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0",
		UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.66 Safari/537.36",
		BaseUri:   fmt.Sprintf("https://%s", website),
		//BaseUri:     "https://www.amazon.com",
		Header: nil,
		//Cookies: nil,
		Cookies:     user.HttpCookies,
		Debug:       true,
		DebugLength: 100000,
		Proxy:       proxy,
		//Proxy:       `http://127.0.0.1:8080`,
		//Proxy: `http://192.168.2.5:8080`,
		//Proxy:       `http://127.0.0.1:24000`,
		//Proxy: `http://FE6FC783:E0C53AF2F7CD@119.114.23.221:45350`,
		//Proxy: `http://lum-customer-c_17e58ad2-zone-residential:Jjyylu102697@zproxy.lum-superproxy.io:22225`,
		//Proxy: fmt.Sprintf("http://%s:%s@tunnel5.qg.net:14295", global.BM_CONFIG.Section("proxy").Key("username").Value(), global.BM_CONFIG.Section("proxy").Key("password").Value()),
		//Proxy: fmt.Sprintf("http://%s:%s@http-dynamic.xiaoxiangdaili.com:10030", global.BM_CONFIG.Section("proxy").Key("username").Value(), global.BM_CONFIG.Section("proxy").Key("password").Value()),
	})

	//isExecute := data["isExecute"].(*bool)
	var responsePath, responseUrl string

	var accountStatistic = make(map[string]map[string]interface{})
	accountStatistic[user.Emailaddress] = make(map[string]interface{})
	accountStatistic[user.Emailaddress] = map[string]interface{}{
		"zipCode":          "",
		"address":          "",
		"cc":               "",
		"purchse_order_id": "",
		"success":          []interface{}{},
		"orders":           []string{},
		"asins":            []string{},
	}

	var reCreateAddress = false
	var reCreateAddressCount = 3
	var reAddCreditCard = false

	continueExecute := true
	for continueExecute {
		//if !*isExecute { //是否继续执行
		//	return
		//}

		switch {
		case resp == nil: // 首页

			switch code {
			case "de", "uk", "fr":
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "打开cookie设置"})
				resp, document, err = amz.Navigate("/cookieprefs")
			default:
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "打开首页"})
				resp, document, err = amz.Navigate("/")
			}

			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				continueExecute = false
			}

			//return
		case responsePath == "/cookieprefs":
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "接受所有cookies"})
			resp, document, err = amz.AcceptAllCookies(document)
			if err != nil {
				resp = nil
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				continue
			}
		case responsePath == "/":
			var postalCode string
			zipCode, _ := global.BM_API.GetZipCode(code, global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value())
			accountStatistic[user.Emailaddress]["zipCode"] = zipCode.ZipCode
			postalCode = zipCode.ZipCode

			resp, err = amz.ChangeAddress(document, postalCode)

			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": resp.Request.TraceInfo().RemoteAddr.String()})
			//resp, err = amz.ChangeAddress(document, amazon.Choice(zipCode))
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				resp = nil
				document = nil
				continue
			} else {
				//if gjson.Get(resp.String(), "isValidAddress").Int() == 1 {
				//	d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group":groupName, "content": fmt.Sprintf("%s -> 邮编无效, 换邮编", postalCode)})
				//	resp, document, err = amz.Navigate("/")
				//} else {
				//	d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group":groupName, "content": fmt.Sprintf("已把地址修改为: %s %s", gjson.Get(resp.String(), "address.city").String(), gjson.Get(resp.String(), "address.zipCode").String())})
				//}
				if gjson.Get(resp.String(), "address.zipCode").String() == "" {
					d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("%s -> 邮编无效, 换邮编", postalCode)})
					resp, document, err = amz.Navigate("/")

					continue
				} else {
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("已把地址修改为: %s %s", gjson.Get(resp.String(), "address.city").String(), gjson.Get(resp.String(), "address.zipCode").String())})

					resp, document, err = amz.Navigate(amazon.TestLogin)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
						continueExecute = false
					}
				}
			}
		case amz.IsSwitchAccount(document):
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "切换登陆账号"})
			resp, document, err = amz.SwitchAccount(document)
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
			}
		case strings.Contains(resp.String(), "auth-error-message-box"):
			d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "账户被锁"})
			//if data["mode"] == "fastMode" {
			//	var taskIds []string
			//	for _, task := range gjson.Get(data["tasks"].(string), "list.#.task_id.value").Array() {
			//		taskIds = append(taskIds, task.String())
			//	}
			//
			//	global.BM_API.RollBackTask(global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value(), taskIds)
			//}

			//
			continueExecute = false
		case responsePath == "/ap/signin": //登录
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "开始登录"})
			resp, document, err = amz.Login(user.Emailaddress, user.Password, document)
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				continueExecute = false
			} else {
				//resp, document, err = amz.Navigate("/") //如果开始没有加载cookies,需要登陆之后再设置邮编，不然会找不到跟卖
			}
		case strings.Contains(responseUrl, "account-status.amazon"), responsePath == "/gp/digital/fiona/manage/order-history", responsePath == "/ap/cvf/transactionapproval":
			d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "账户失效"})
			continueExecute = false
		case responsePath == "/ap/accountfixup": //是否绑定手机
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "跳过绑定手机"})
			resp, document, err = amz.AccountFixup(document)
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				continueExecute = false
			}
		case responsePath == "/gp/yourstore": //下单之后可能跳回这里
			resp, document, _ = amz.Navigate(amazon.TaskPage)
		case responsePath == amazon.TaskPage, responsePath == amazon.TestLogin: // 在任务页面做任务或者尝试登陆页面做任务
			//检查是否需要登录
			checkLoginResp, _, checkLoginErr := amz.Navigate(amazon.TestLogin)
			if checkLoginErr != nil {
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				continue
			} else {
				if checkLoginResp.RawResponse.Request.URL.Path == "/ap/signin" {
					d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "账户失效"})
					continueExecute = false
					continue
				}
			}

			taskList := gjson.Get(data["tasks"].(string), "list").Array()
			taskTotal := len(taskList)

			// 并发加购多个产品
			dataDomain := `https://data.amazon.com`
			switch code {
			case "de":
				dataDomain = `https://data.amazon.de`
			case "uk":
				dataDomain = `https://data.amazon.co.uk`
			case "ca":
				dataDomain = `https://data.amazon.ca`
			case "au":
				dataDomain = `https://data.amazon.com.au`
			case "jp":
				dataDomain = `https://data.amazon.co.jp`
			}

			amz.Telnet(dataDomain)
			var chans []chan interface{}
			var asins []string
			for _, task := range taskList {
				quantity := 999 / taskTotal
				asin := gjson.Get(task.String(), "asin.value").String()
				sellerId := gjson.Get(task.String(), "seller_id.value").String()
				email := user.Emailaddress
				var ch = make(chan interface{})
				chans = append(chans, ch)
				asins = append(asins, asin)
				global.BM_POOL.Submit(d.Decorator(d.AddCartThread, map[string]interface{}{
					"asin":      asin,
					"seller_id": sellerId,
					"quantity":  quantity,
					"email":     email,
					"group":     groupName,
					"zipcode":   accountStatistic[user.Emailaddress]["zipCode"],
					"amz":       amz,
				}, &addcartWg, ch))
			}

			addcartWg.Wait()

			resetTask := true
			var successTotal = 0
			for _, ch := range chans {
				chResult := <-ch
				if chResult != nil {
					result := chResult.(map[string]string)
					if _, ok := result["status"]; ok {
						resetTask = false
						successTotal++
						if err != nil {
							d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})

						}
					}
				}
			}

			if successTotal == 0 {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("%s 都无法加入购物车, 退出", strings.Join(asins, ", "))})
				//continueExecute = false //cc信用卡需要退出
				resetTask = true
			}

			if resetTask {
				resp, document, _ = amz.Navigate(amazon.TaskPage)
			} else {
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "加购完毕, 进入购物车"})

				resp, document, err = amz.Navigate(amazon.Cart)
			}
		case responsePath == "/gp/css/order-history": //提取订单号
			orderId := amz.ExtractOrderId(document)
			if orderId != "" { // 如果订单号空那么就是订单已经被取消
				d.sendLog(map[string]string{"status": "success", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("订单号:%s", orderId)})
				accountStatistic[user.Emailaddress]["orders"] = append(accountStatistic[user.Emailaddress]["orders"].([]string), orderId)
			}

			//信用卡最大次数
			//if len(accountStatistic[user.Emailaddress]["orders"].([]string)) > 7 {
			if len(accountStatistic[user.Emailaddress]["orders"].([]string)) > 1000 {
				goodCC := fmt.Sprintf("%s-6", accountStatistic[user.Emailaddress]["cc"].(string))
				global.BM_API.FeedBackCreditCard(goodCC, code)
				continueExecute = false
			} else {
				if len(accountStatistic[user.Emailaddress]["orders"].([]string)) == 1 {
					global.BM_API.FeedBackCreditCard(accountStatistic[user.Emailaddress]["cc"].(string), code)
				}

				if isCancel {
					//取消订单必须大量下单，因为库存回的很快
					resp, document, err = amz.CancelOrder(document)
				} else {
					//如果不取消订单就在这里等待下一单，如果取消订单，就注释这里，在取消订单成功那里等待下一单
					var ch = make(chan interface{})
					global.BM_POOL.Submit(d.Decorator(d.HeartbeatThread, map[string]interface{}{
						"amz":       amz,
						"email":     user.Emailaddress,
						"pauseTime": pauseTime,
						"group":     groupName,
					}, &heartbeatWg, ch))

					heartbeatWg.Wait()

					for {
						chResult := <-ch
						result := chResult.(bool)
						if result {
							resp, document, err = amz.Navigate(amazon.TaskPage)
							break
						} else {
							d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "账户已失效, 退出"})
							continueExecute = false
							break
						}
					}
				}
			}
			//resp, document, err = amz.Navigate(amazon.TaskPage)
		case responsePath == "/gp/css/order/edit.html/ref=ppx_yo_dt_b_ci_o00_s00", responsePath == "/gp/css/order/edit.html": //无法取消订单，需要重试:
			resp, document, err = amz.ConfirmCancelOrder(document)
		case responsePath == "/gp/your-account/order-details/ref=_or":
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "订单取消成功"})

			var ch = make(chan interface{})
			global.BM_POOL.Submit(d.Decorator(d.HeartbeatThread, map[string]interface{}{
				"amz":       amz,
				"email":     user.Emailaddress,
				"pauseTime": pauseTime,
				"group":     groupName,
			}, &heartbeatWg, ch))

			heartbeatWg.Wait()
			for {
				chResult := <-ch
				result := chResult.(bool)
				if result {
					resp, document, err = amz.Navigate(amazon.TaskPage)
					break
				} else {
					d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "账户已失效, 退出"})
					continueExecute = false
					break
				}
			}
		case responsePath == "/gp/cart/view.html": //购物车
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "开始结账"})
			resp, document, err = amz.Checkout(document)
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("%s -> %s, 重新开始任务", user.Emailaddress, err.Error())})
				resp, document, _ = amz.Navigate(amazon.TaskPage)
				//return
			}
		case amz.IsSelectAddressPage(resp, document): //收货地址页面
			if amz.CanSelectAddress(document) && !reCreateAddress { // 如果可以选择收货地址，直接选择，不需要填写
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "选择收货地址或者账单地址"})
				resp, document, err = amz.SelectAddress(document)
				if err != nil {
					d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("%s, 重新开始任务", err.Error())})
					resp, document, _ = amz.Navigate(amazon.TaskPage)
				}

			} else { // 提交收货地址
				// 获取地址信息
				if reCreateAddressCount <= 0 { // 如果尝试重建地址超过3次就不再执行
					continueExecute = false
				}

				var suggestions amazon.AddressSuggestions
				var searchText string

				address, _ := global.BM_API.GetShippingAddress(code, global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value())

				switch code {
				case "uk":
					searchText = address.ZipCode
				case "de":
					searchText = address.Address1
					//suggestions.City = address.City
					//suggestions.StateOrRegion = address.State
					//suggestions.Phone = address.Phone
					//suggestions.AddressLine1 = address.Address1
					//suggestions.AddressLine2 = address.Address2
					//suggestions.PostalCode = address.ZipCode
					//suggestions.Recipient = address.Recipient
				case "ca", "au":
					suggestions.City = address.City
					suggestions.StateOrRegion = address.State
					suggestions.Phone = address.Phone
					suggestions.AddressLine1 = address.Address1
					suggestions.AddressLine2 = address.Address2
					suggestions.PostalCode = address.ZipCode
					suggestions.Recipient = address.Recipient
				default:
					searchText = strconv.Itoa(amazon.RandomInt(1, 10000))
					//suggestions, err = amz.AddressSuggestion(code, searchText)
					//if err != nil {
					//	d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group":groupName,  "content": err.Error()})
					//	continueExecute = false
					//}
					//
					//suggestions.Phone = address.Phone
					//suggestions.Recipient = address.Recipient
					//addressInfo := fmt.Sprintf(`address = %s, postcode = %s, city = %s, state = %s`, suggestions.AddressLine1, suggestions.PostalCode, suggestions.City, suggestions.StateOrRegion)
					//d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group":groupName,  "content": fmt.Sprintf("%s 随机的收货地址: %s", user.Emailaddress, addressInfo)})
					//accountStatistic[user.Emailaddress]["address"] = addressInfo
				}

				var addressInfo string
				switch code {
				case "ca", "au":
				default:
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("获取收货地址, 关键字: %s", searchText)})

					suggestions, err = amz.AddressSuggestion(code, searchText)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
						continueExecute = false
					}

					suggestions.Phone = address.Phone
					suggestions.Recipient = address.Recipient

					var addressline string
					if suggestions.AddressLine1 != "" {
						addressline = suggestions.AddressLine1
					} else if suggestions.AddressLine2 != "" {
						addressline = suggestions.AddressLine2
					}

					addressInfo = fmt.Sprintf(`address = %s, postcode = %s, city = %s, state = %s`, addressline, suggestions.PostalCode, suggestions.City, suggestions.StateOrRegion)
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("随机的收货地址: %s", addressInfo)})
				}

				accountStatistic[user.Emailaddress]["address"] = addressInfo

				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "添加收货地址"})
				resp, document, err = amz.SubmitCheckoutAddress(suggestions, document)
				if err != nil {
					d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
					continueExecute = false
				}

				reCreateAddressCount--
				reCreateAddress = false //重置

			}
		//case amz.IsItemSelectPage(document):
		//	d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group":groupName,  "content": "无法配送产品, 尝试下单"})
		//	resp, document, _ = amz.Navigate(`/gp/buy/spc/handlers/display.html?hasWorkingJavascript=1`)
		//	//time.Sleep(1 * time.Minute)
		//	//resp, document, _ = amz.Navigate(amazon.TaskPage)
		case amz.IsSelectPaymentMethodPage(resp, document): //付款页面
			if amz.CanSelectCreditCard(document) && !reAddCreditCard { // 如果可以选择信用卡，直接选择，不需要填写
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "选择信用卡"})
				resp, document, err = amz.SelectPaymentMethod(document)
				if err != nil {
					d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
					continueExecute = false
				}
			} else if amz.CanSelectCheque(document) {
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "选择支票"})
				resp, document, err = amz.SelectPaymentMethod(document)
				if err != nil {
					d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
					continueExecute = false
				}
			} else { // 提交信用卡
				switch code {
				case "ca", "au", "jp", "uk":
					/* // 信用卡方 */
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "获取信用卡信息"})

					creditCard, err := global.BM_API.GetCreditCard(code, global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value())

					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "获取信用卡失败"})
						continueExecute = false
					}

					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "获取信用卡表单"})
					resp, document, err = amz.GetCheckOutCreditCardForm(document)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
						continueExecute = false
					}

					//creditCard.CardNo = "4475890329687224" //澳大利亚下很多单的
					//creditCard.CardNo = "4007898420454367"
					//creditCard.CardNo = "4539412852660660"
					//creditCard.CardNo = "4556451611239992" //加拿大pending单，复现不了
					//creditCard.CardNo = "5173830004463170" //英国 存活9分钟以上， 下单时候需要验证信用卡，3分钟内，取消，取消原因选择need change payment method
					//creditCard.CardNo = "5227866234848117" // 加拿大, 有点坚挺，未做第二次测试
					//creditCard.ValidPeriod = "11/2026"
					//accountStatistic[user.Emailaddress]["cc"] = creditCard.CardNo
					resp, document, err = amz.SubmitCheckoutCreditCard(creditCard.Name, creditCard.CardNo, creditCard.Cvv, creditCard.ValidPeriod, document)

					//accountStatistic[user.Emailaddress]["cc"] = user.CreditCard.CardNo
					//resp, document, err = amz.SubmitCheckoutCreditCard(user.Address.Recipient, user.CreditCard.CardNo, user.CreditCard.Cvv, user.CreditCard.ValidPeriod, document)

					if err != nil {

						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf(`提交的信用卡是: %s, 错误信息: %s `, creditCard.CardNo, err.Error())})
						// 重新尝试别的信用卡
						d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "换新的信用卡"})
						resp, document, err = amz.Navigate(`/gp/buy/payselect/handlers/display.html?hasWorkingJavascript=1`)
						continue
					} else {
						d.sendLog(map[string]string{"status": "success", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("成功添加信用卡, 信用卡号: %s", creditCard.CardNo)})
						d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": resp.String()})
					}

					resp, document, err = amz.Navigate(`/gp/buy/payselect/handlers/display.html?hasWorkingJavascript=1`)

					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
						continueExecute = false
					}

					resp, document, err = amz.SelectPaymentMethod(document)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
					}

					reAddCreditCard = false //重置信用卡
				case "de", "fr":
					// 银行账户方式
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "获取银行账户信息"})

					cheque, err := global.BM_API.GetCheque(code, global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value())

					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "获取银行账户失败"})
						continueExecute = false
					}
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "获取银行账户表单"})
					document, err = amz.GetCheckOutCheckingForm(document)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
						continueExecute = false
					}

					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("提交银行账户信息 => %s", cheque.ChequeNumber)})
					resp, err = amz.SubmitCheckoutBank(cheque.Name, cheque.RoutingNumber, cheque.ChequeNumber, document)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "content": err.Error()})
						continueExecute = false
					} else {
						d.sendLog(map[string]string{"status": "info", "content": resp.String()})
					}

					resp, document, err = amz.Navigate(`/gp/buy/payselect/handlers/display.html?hasWorkingJavascript=1`)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "content": err.Error()})
						continueExecute = false
					}
					resp, document, err = amz.SelectPaymentMethod(document)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "content": err.Error()})
					}
				case "us":
					//支票付款方式
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "获取支票信息"})

					cheque, err := global.BM_API.GetCheque(code, global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value())

					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "获取支票失败"})
						continueExecute = false
					}
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "获取支票表单"})
					document, err = amz.GetCheckOutCheckingForm(document)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
						continueExecute = false
					}

					cheque.ChequeNumber = "00007267377865451"
					d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("提交支票信息 => Routing:%s, Number:%s", cheque.RoutingNumber, cheque.ChequeNumber)})

					resp, err = amz.SubmitCheckoutChecking(cheque.Name, cheque.RoutingNumber, cheque.ChequeNumber, cheque.SocialNumber, cheque.State, document)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "content": err.Error()})
						continueExecute = false
					} else {
						d.sendLog(map[string]string{"status": "info", "content": resp.String()})
					}

					resp, document, err = amz.Navigate(`/gp/buy/payselect/handlers/display.html?hasWorkingJavascript=1`)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "content": err.Error()})
						continueExecute = false
					}
					resp, document, err = amz.SelectPaymentMethod(document)
					if err != nil {
						d.sendLog(map[string]string{"status": "error", "content": err.Error()})
					}
				}
			}
		case strings.Contains(resp.String(), "noPrefetch"): // 有时候提交信用卡会返回这个，重试
			resp, document, err = amz.Navigate(`/gp/buy/payselect/handlers/display.html?hasWorkingJavascript=1`)
		case responsePath == "/cpe/executions": //需要验证信用卡（韩国的货币卡好像需要验证）
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "需要验证信用卡, 开始验证信用卡..."})
			resp, document, err = amz.VerifyCreditCard(resp, document)
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("%s, 重新下单", err.Error())})
				resp, document, err = amz.Navigate(amazon.TaskPage)
				reAddCreditCard = true
			}

		case amz.IsNeedRedirectIemSelectPage(resp), amz.IsItemSelectPage(document), amz.IsCheckoutAddressIntercept(document):
			if strings.Contains(resp.String(), "outOfStock") {
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "产品不可售了"})
				continueExecute = false
			} else {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "此地址不在配送范围, 重选地址"})
				reCreateAddress = true
				resp, document, err = amz.Navigate(`/gp/buy/addressselect/handlers/display.html?hasWorkingJavascript=1`)
			}
		case amz.IsNeedRedirectSharedPage(resp):
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "添加完地址后需要跳转"})
			redirectUrl := gjson.Get(resp.String(), "conductoraction.url").String()
			resp, document, err = amz.Navigate(redirectUrl)
		case amz.IsPrimePage(document): // 成为会员页面
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "不需要Prime"})
			resp, document, err = amz.NotNeedPrime(document)
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				continueExecute = false
			}
		case amz.IsPlaceOrderdPage(document):
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "确认下单"})

			resp, document, err = amz.PlaceOrder(document)
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				continueExecute = false
			}
		case amz.IsNeedConfirmOrder(document):
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "需要确认订单"})

			resp, document, err = amz.ConfirmOrder(document)
			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
			} else {
				d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "确认下重复订单"})
			}
		case amz.IsCompleteOrderPage(document): // 如果需要提取下单链接，就提取
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "提取执行下单链接"})
			resp, document, err = amz.CompleteOrder(document)

			if err != nil {
				d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": err.Error()})
				resp, document, err = amz.Navigate(amazon.TaskPage)
			}

		case amz.IsSoldOutPage(document):
			d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "产品没有库存, 重新开始任务"})
			// 回到任务开始的地方,重新开始任务
			resp, document, _ = amz.Navigate(amazon.TaskPage)
		case amz.IsPlaceOrderSuccess(document): //正常成功下单页面
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "成功下单, 进入订单历史页获取订单号"})

			//统计asin购买次数
			//document.Find("div[cel_widget_id='typ-shipmentProductImages'] ul li a[id^='image-link']").Each(func(i int, selection *goquery.Selection) {
			//	href, exists := selection.Attr("href")
			//	if exists {
			//		parse, err := url.Parse(href)
			//		if err == nil {
			//			successAsin := strings.Split(parse.Path, "/")[2]
			//			accountStatistic[user.Emailaddress]["success"] = append(accountStatistic[user.Emailaddress]["success"].([]interface{}), successAsin)
			//			accountStatistic[user.Emailaddress]["asins"] = append(accountStatistic[user.Emailaddress]["asins"].([]string), successAsin)
			//			global.BM_API.FeedBack(successAsin, global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value())
			//		}
			//	}
			//})
			taskList := gjson.Get(data["tasks"].(string), "list").Array()
			var tasksId []string
			for _, task := range taskList {
				tasksId = append(tasksId, gjson.Get(task.String(), "task_id.value").String())
			}
			global.BM_API.FeedBack(strings.Join(tasksId, ","), global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value())

			resp, document, _ = amz.Navigate(amazon.OrderHistory)
		case responsePath == "/gp/buy/thankyou/handlers/display.html": //是下单成功链接，但是没有购买产品的信息
			d.sendLog(map[string]string{"status": "info", "email": user.Emailaddress, "group": groupName, "content": "下单可能成功, 尝试进入订单历史页获取订单号"})
			resp, document, _ = amz.Navigate(amazon.OrderHistory)
		default:
			d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": fmt.Sprintf("未知内容, 退出, 当前页面: %s", responseUrl)})

			ioutil.WriteFile("unknown.html", resp.Body(), 0644)
			//continueExecute = false //cc信用卡需要退出
			resp, document, _ = amz.Navigate(amazon.TaskPage)
		}

		if resp != nil {
			responsePath = resp.RawResponse.Request.URL.Path
			responseUrl = resp.RawResponse.Request.URL.String()
		}
	}

	global.BM_EVENTBUS.Publish(fmt.Sprintf("%s:deleteData", d.Topic), groupName)

	var statistic map[string]string
	total := utils.ArrayCountValues(accountStatistic[user.Emailaddress]["success"].([]interface{}))
	global.BM_EVENTBUS.Publish("deals:feedback", total)

	statisticFormat := fmt.Sprintf("\n 邮箱    : %s\t\n 邮编    : %s\n 收货地址: %s\n 信用卡号: %s\n asins:   %s\n 订单总数: %d\n 订单列表: %s\n===========================================",
		user.Emailaddress,
		accountStatistic[user.Emailaddress]["zipCode"],
		accountStatistic[user.Emailaddress]["address"],
		accountStatistic[user.Emailaddress]["cc"],
		strings.Join(utils.RemoveDuplicateStr(accountStatistic[user.Emailaddress]["asins"].([]string)), "\t"),
		len(accountStatistic[user.Emailaddress]["orders"].([]string)),
		strings.Join(accountStatistic[user.Emailaddress]["orders"].([]string), "\t"),
	)

	d.EndFeedBack(data["tasks"], len(accountStatistic[user.Emailaddress]["orders"].([]string)))

	statistic = map[string]string{"status": "info", "content": statisticFormat}

	return statistic
}

//func (d *DealsCheckoutWorker) Heartbeat(amz *amazon.Amazon, user *utils.User, pauseTime int64, groupName string, resp *mamba.Response, document *goquery.Document, err error, continueExecute bool) {
//	var heartbeatWg sync.WaitGroup
//	var ch = make(chan interface{})
//	global.BM_POOL.Submit(d.Decorator(d.HeartbeatThread, map[string]interface{}{
//		"amz":       amz,
//		"email":     user.Emailaddress,
//		"pauseTime": pauseTime,
//		"group": groupName,
//	}, &heartbeatWg, ch))
//
//	heartbeatWg.Wait()
//
//	for {
//		chResult := <- ch
//		result := chResult.(bool)
//		if result {
//			resp, document, err = amz.Navigate(amazon.TaskPage)
//			break
//		} else {
//			d.sendLog(map[string]string{"status": "error", "email": user.Emailaddress, "group": groupName, "content": "账户已失效, 退出"})
//			continueExecute = false
//			break
//		}
//	}
//
//	return
//}
func (d *DealsCheckoutWorker) EndFeedBack(tasks interface{}, total int) {
	var taskIds []string
	for _, task := range gjson.Get(tasks.(string), "list.#.task_id.value").Array() {
		taskIds = append(taskIds, task.String())
	}
	//time.Sleep(5 * time.Second)
	//global.BM_API.EndFeedBack(global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value(), strings.Join(taskIds, ","), 10)
	global.BM_API.EndFeedBack(global.BM_CONFIG.Section("basic").Key("serialNumberCiphertext").Value(), strings.Join(taskIds, ","), total)
}
